package com.kx.base.util;

import java.lang.ref.Reference;
import java.lang.ref.SoftReference;

/**
 * 使用双向链表实现
 * 内存缓存组件  LRU算法(删除最近最少使用元素)
 * 1、使用LRU算法进行内存淘汰。
 * 2、使用软引用，来避免因为LRU算法导致原本的SSM模型内存不够用。
 *
 * @Author Sun
 * @Date 2021/7/30 21:22
 */
public class CacheUtil {
    /**
     * 链表的头
     */
    private Node top;
    /**
     * 链表的尾
     */
    private Node bottom;
    /**
     * 缓存区的大小（缓存对象的个数）
     */
    private Integer size;
    /**
     * 当前元素个数
     */
    private int length;

    public CacheUtil(int size) {
        this.size = size;
    }

    /**
     * 向缓存区添加元素
     */
    public void put(String key, Object value) {
        synchronized (size) {
            if (length > 0) {
                //先判断元素存不存在，存在直接删除然后头部插入元素，不存在直接头部插入
                for (Node p = top; p.next != null; p = p.next) {
                    if (key.equals(p.key)) {
                        //元素重复，删除当前元素，将新元素添加进来
                        if (p == top) {
                            //第一个元素
                            top = top.next;
                        } else if (p == bottom) {
                            //最后一个元素
                            bottom = bottom.prev;
                            bottom.next = null;
                        } else {
                            //中间元素
                            p.next.prev = p.prev;
                            p.prev.next = p.next;
                        }
                        length--;
                    }
                }
            }
            //实例了一个软引用
            SoftReference<Object> softReference = new SoftReference<>(value);
            //头插尾删
            if (length == 0) {
                top = new Node();
                bottom = top;
                top.key = key;
                top.value = softReference;
                length++;
                return;
            }
            if (length == size) {
                //头部插入
                Node temp = new Node();
                temp.next = top;
                top.prev = temp;
                temp.key = key;
                temp.value = softReference;
                top = temp;
                if (length < size) {
                    length++;
                }
            }
            if (length >= size) {
                //尾部删除
                bottom.prev = bottom;
                bottom.next = null;
            }
        }

    }

    /**
     * 从缓冲区获取元素
     */
    public Object get(String key) {
        synchronized (size) {
            //找到元素后删除元素，然后头部插入
            if (length == 0) {
                return null;
            } else {
                //链表版的标准for循环
                for (Node p = top; p.next != null; p = p.next) {
                    if (p.key.equals(key)) {
                        if (p == top) {
                            Object object = p.value.get();
                            if (object == null) {
                                //说明软引用的对象被回收了
                                top = top.next;
                                length--;
                                return null;
                            } else {
                                return object;
                            }
                        }
                    }
                    if (p.next != null) {
                        //说明当前节点一定不是尾节点
                        p.next.prev = p.prev;
                        p.prev.next = p.next;
                        Object object = p.value.get();
                        if (object == null) {
                            length--;
                            return null;
                        } else {
                            //将元素插入到头结点
                            p.next = top;
                            top.prev = p;
                            top = p;
                            p.prev = null;
                            return object;
                        }
                    } else {
                        //一定是尾节点
                        bottom = bottom.prev;
                        Object object = p.value.get();
                        if (object == null) {
                            length--;
                            return null;
                        } else {
                            //将元素插入到头结点
                            p.next = top;
                            top.prev = p;
                            top = p;
                            p.prev = null;
                            return object;
                        }
                    }
                }
            }
        }
        return null;
    }

    /**
     * 定义双向链表
     */
    private class Node {
        private Node prev;
        private Node next;
        private String key;
        //定义为软引用，当内存不足时可以进行回收
        private Reference<Object> value;
    }
}
